let marriged:boolean = true;
let age:number = 10;
let first_name:string = 'mike'
let arr1:number[] = [1,2,3];
let arr2: Array<number> = [4,5,6]

let arr3:string[]=['1','2','3']
let arr4:Array<string|number|object|boolean>=[1,2,'3',{},false]
// 元组类型tuple 数量和类型已知的数组
let zhufeng:[string,number]=['zhufeng',12];
let zhufeng1:[string|number,string]=[1,'string']
// 普通枚举
enum Gender{
    GIRL,
    BOY
}
console.log(Gender.GIRL, Gender[0])
console.log(Gender.BOY, Gender[1])
// 常量枚举
const enum Colors{
    RED,YELLOW,BLUE
}
let myColor = [Colors.RED,Colors.BLUE,Colors.YELLOW]
// 任意类型
// any
// 如果变量定义为any类型，就跟JS差不多，不进行类型检查
let root:any = document.getElementById('root');
root.style.color = 'red';

let element: (HTMLElement | null) = document.getElementById('root')
element!.style.color = 'green'; // 这里！强调element一定会有值

// null undefined
// 如果说strictNullChecks的值为true，则不能把null undefined的值赋给x
let x: number;
x=1
// x=undefined
// x=null
let z:undefined = undefined
let z2:any = undefined

let y: number|null|undefined;
y=1;
y=undefined
y=null;

// never 作为不会返回的函数的返回值 类型
function error(message:string):never{
    throw new Error('报错了'); //直接异常结束
    console.log('ok')
}

function loop():never{
    console.log(12)
    while(true){

    }
}
function fn(x:number|string){
    if(typeof x === 'number'){
        console.log(x)
    } else if(typeof x === 'string'){
        console.log(x)
    } else {
        console.log(x) // never 这里的x类型就是never
    }
}
// void 代表没有任何类型
// 如果一个函数没有返回的值，那么就是void类型
function greeting():void{
    return undefined; 
    //  // 如果让 strictNullChecks 为 false，则此处可以return false
}
// 区别：void可以被赋值为null undefined nver不能包含任何类型
// 返回类型为viod的函数还能执行，但是返回never的函数无法正常执行

// Symbol
const s1 = Symbol('key');
const s2 = Symbol('key');
// console.log(s1 === s2)

// BigInt
// const max = Number.MAX_SAFE_INTEGER; // 2**53-1
// console.log(max+1 === max+2)

const max = BigInt(Number.MAX_SAFE_INTEGER);
console.log(max+BigInt(1)===max+BigInt(2))
console.log(max+1n===max+2n)

// 类型推导，

// 
let isOk1: boolean = true
let isOk2: boolean = Boolean(1)
// let isOk3: boolean = new Boolean(2)

// 联合类型, 
let name3: string | number
console.log(name3!.toString()) // 此处.后只会出现两个类型的共有方法
name3 = 3
console.log(name3.toFixed(2))  // 一旦赋值为3后，就可以调用 nubmer的方法
name3 = 'hello'
console.log(name3.length)   // 同样的，如果赋值为 'hello' 后，就可以使用string的方法了

// 类型断言
let name4:string|number
console.log((name4! as number).toFixed(2))
console.log((name4! as string).length)
// 双重断言
// console.log((name4! as boolean).length) 设置了类型，但是这里改成了boolean就有问题了
console.log((name4! as any as boolean))

// 字面量类型 和 类型字面量
// 字面量类型直接是把值 赋值给类型
// 
const up1: 1|'male'|boolean = 1 
const up: 'Up'= 'Up' 
const down: 'Down'= 'Down' 
const left: 'Left'= 'Left' 
const right: 'Right'= 'Right' 
type Direction = 'Up'|'Down'|'Left'|'Right'
// 可实现枚举的效果
function move(direction: Direction){

}
move("Down")

// 类型字面量
type Person = {
    name: string,
    age: number
}
let p1: Person={
    name: 'mike',
    age: 13
}
// 字符串字面量和联合类型
type T1 = '1'|'2'|'3'
type T2 = number|string|boolean
let t1:T1 = '1'
let t2:T2 = true

// 类型：unknown 表示未知类型
// 下面是unknown 和 any的区别
// unknown就是一个类型安全的any
let f: any
let e: unknown
//  e = 10
//  e = 'hello'
//  e = true
let s:string;
e = 'hello'
// s = e  // 此处就会报错，因为不能把string类型赋值给 s
f = false
// s = f  // 此处不会报错，因为any类型可以赋值给任何类型的值

// 类型断言, 可以用来告诉解析器变量的实际类型
s = e as string
s = <string>e